Next | Prev | Up | Top | Contents | Index
Upper and Lower Halves
When a device can produce hardware interrupts, its kernel-level device driver has two distinct logical parts, called the "upper half" and the "lower half" (although the upper "half" usually has much more than half the code).
Driver Upper Half
The upper half of a driver comprises all the parts that are invoked as a result of user process calls: the driver entry points that execute in response to open(), close(), ioctl(), mmap(), read() and write().
These parts of the driver are called on behalf of a specific process. This is referred to as "having user context," which means that they are executed under the identity of a specific process.
As a result, code in the upper half of the driver is allowed to request kernel services that can be delayed, or "sleep." For example, code in the upper half of a driver can call kmem_alloc() to request memory in kernel space, and can specify that if memory is not available, the driver can sleep until memory is available. Also, code in the upper half can wait on a semaphore until some event occurs, or can seize a lock knowing that it may have to sleep until the lock is released.
In each case, the entire kernel does not "sleep." The driver upper half sleeps under the identity of the user process; the kernel dispatches other processes to run. When the blocking condition is removed--when memory is available, the semaphore is posted, or the lock is released--the driver is scheduled for execution and resumes.
Driver Lower Half
The lower half of a driver comprises the code that is called to respond to a hardware interrupt. An interrupt can occur at almost any time, including large parts of the time when the kernel is executing other services, including driver upper halves, and even driver lower halves for devices with lower-priority interrupts.
The kernel is not in a known state when executing a driver lower half, and there is no process context. Several things follow from this fact:
- It is very important that the interrupt be handled in the absolute minimum of time, since it may be delaying a kernel service or even the handling of a lower-priority interrupt.
- The lower-half code may not use any kernel service that can sleep (because there is no dispatchable process to be blocked and dispatched again later). Every authorized kernel service is documented as to whether it can sleep or not.
Relationship Between Halves
Each half has its proper kind of work. In general terms, the upper half performs all validation and preparation, including allocating and deallocating memory and copying data between address spaces. It initiates the first device operation of a series and queues other operations. Then it waits on a semaphore.
The lower half verifies the correct completion of an operation. If another operation is queued, it initiates that operation. Then it posts the semaphore to awaken the upper half, and exits.
Next | Prev | Up | Top | Contents | Index